package processes

import (
	"util"
)

const weight = 1000             //x1 x2  放大倍数
const weightx3 = 100000         //x3 放大倍数
const para1, para2 = 100, 10000 //数据放大倍数（万分之）
// 安全打法 x1 x2 减2000 x3 减 20000
var methodFuncs [util.AmountOfMethodStyle][util.AmountOfMethodType]methodFunc

type methodFunc func(x1, x2, x3 int32, price, capital int64) (*util.MethodResult, int64)

func init() {
	methodFuncs = [util.AmountOfMethodStyle][util.AmountOfMethodType]methodFunc{
		{methodNumber4, methodNumber5, methodNumber6},
		{methodNumber1, methodNumber2, methodNumber3},
		{methodNumber7, methodNumber8, methodNumber9}}
}
func GetMethodResult(methodStyle util.MethodStyle, methodType util.MethodType, x1, x2, x3 int32, price, capital int64) (*util.MethodResult, int64) {
	return methodNumber0(x1, x2, x3, price, capital)
}

/*打法0 全部加第一仓*/
func methodNumber0(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) { //返回实际用到的加仓金额
	methodResult = new(util.MethodResult)
	methodResult.Prices = []int64{price}
	methodResult.Capitals = []int64{capital}
	methodResult.Pos = []int32{0}
	actualCapital = capital
	return
}

/*
打法1 固定出击份额的二仓出击位置函数 （保守）
出击位置1=0
出击位置2=max{ -2.22 +( -1.12 )*x1+( -0.59 )*x2+( 10.82 )*x3,出击位置1}
出击份额1=0.5
出击份额2=1-出击份额1
预测收益率= 1.08 +( 0.79 )*x1+( -0.05 )*x2+( -1.8 )*x3
*/
func methodNumber1(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) { //返回实际用到的加仓金额
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	capital1 := int64(float64(capital)*0.5 + 0.5)
	methodResult.Prices = []int64{price1} //加第一仓
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((-2.22-1.12*xx1-0.59*xx2+10.82*xx3)*para1+0.5))
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	capital2 := capital - capital1
	if pos2 >= para2 { //只打第一仓
		return
	}
	if price1 == price2 { //出击位置1跟出击位置2相同 合并
		methodResult.Capitals[0] = capital
		actualCapital = capital // methodResult.Capitals[0]
		return
	}
	methodResult.Prices = append(methodResult.Prices, price2)
	methodResult.Capitals = append(methodResult.Capitals, capital2)
	methodResult.Pos = append(methodResult.Pos, int32(pos2))
	actualCapital = capital
	return
}

/*
打法2 不定出击份额的二仓出击位置函数 （保守）
出击位置1=0
出击位置2= max{ -2.28 +( -1.2 )*x1+( -0.56 )*x2+( 10.99 )*x3,出击位置1}
出击份额1=min{0.27 +( 0.0 )*x1+( -0.0 )*x2+( 0.03 )*x3,1}
出击份额2=1-出击份额1
预测收益率= 1.66 +( 0.74 )*x1+( -0.07 )*x2+( -2.8 )*x3
*/
func methodNumber2(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	share1 := util.FMin(0.27+0*xx1-0.0*xx2+0.03*xx3, 1)
	share1 = util.FMax(0, share1)
	capital1 := int64(float64(capital)*share1 + 0.5)
	if capital1 == capital { //全加第一仓
		methodResult.Prices = []int64{price1}
		methodResult.Capitals = []int64{capital}
		methodResult.Pos = []int32{0}
		actualCapital = methodResult.Capitals[0]
		return
	}
	if capital1 == 0 { //如果份额等于0
		return
	}
	methodResult.Prices = []int64{price1}
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((-2.28+(-1.2)*xx1+(-0.56)*xx2+(10.99)*xx3)*para1+0.5))
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	capital2 := capital - capital1
	if pos2 >= para2 { //只打第一仓
		return
	}
	if price1 == price2 { //出击位置1跟出击位置2相同 合并
		methodResult.Capitals = []int64{capital}
		actualCapital = capital
		return
	}
	//加第二仓
	methodResult.Prices = append(methodResult.Prices, price2)
	methodResult.Capitals = append(methodResult.Capitals, capital2)
	methodResult.Pos = append(methodResult.Pos, int32(pos2))
	actualCapital = capital
	return
}

/*
打法3 不定出击份额的三仓出击位置函数 （保守）
出击位置1=0
出击位置2=max{ -2.23 +( -0.01 )*x1+( -1.16 )*x2+( 4.79 )*x3,出击位置1}
出击位置3=max{ 2.01 +( 0.46 )*x1+( -0.43 )*x2+( 10.94 )*x3,出击位置2}
出击份额1=0.2
出击份额2=min{ 0.41 +( 0.07 )*x1+( -0.01 )*x2+( -0.11 )*x3,1-出击份额1}
出击份额3=1-出击份额1-出击份额2
预测收益率= 1.23 +( 0.62 )*x1+( -0.09 )*x2+( -2.21 )*x3
*/
func methodNumber3(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	share1 := 0.2
	capital1 := int64(float64(capital)*share1 + 0.5)
	methodResult.Prices = []int64{price1}
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((-2.23+(-0.01)*xx1+(-1.16)*xx2+(4.79)*xx3)*para1+0.5))
	if pos2 >= para2 { //只打第一仓
		return
	}
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	share2 := util.FMin(0.41+(0.07)*xx1+(-0.01)*xx2+(-0.11)*xx3, 1-share1)
	share2 = util.FMax(share2, 0)
	capital2 := int64(float64(capital)*share2 + 0.5)
	if capital2 == 0 { //第二仓分额 小于等于0 全仓打位置1
		methodResult.Capitals = []int64{capital}
		actualCapital = methodResult.Capitals[0]
		return
	}
	if price1 == price2 { //如果价格相等时
		methodResult.Capitals[0] += capital2
		actualCapital = methodResult.Capitals[0]
	} else {
		methodResult.Prices = append(methodResult.Prices, price2)
		methodResult.Capitals = append(methodResult.Capitals, capital2)
		methodResult.Pos = append(methodResult.Pos, int32(pos2))
		actualCapital += capital2
	}
	pos3 := util.Max(int64((2.01+(0.46)*xx1+(-0.43)*xx2+10.94*xx3)*para1+0.5), pos2)
	price3 := int64((float64(price1) * (para2 - float64(pos3)) / para2) + 0.5)
	capital3 := capital - capital1 - capital2
	if pos3 >= para2 { //只加第一仓 第二仓
		return
	}

	if capital3 == 0 { //只加前两仓
		return
	}
	if price2 == price3 { //判断你第三仓跟第二仓价格是否相等
		methodResult.Capitals[len(methodResult.Capitals)-1] += capital3
		actualCapital = capital
		return
	}
	methodResult.Prices = append(methodResult.Prices, price3)
	methodResult.Capitals = append(methodResult.Capitals, capital3)
	methodResult.Pos = append(methodResult.Pos, int32(pos3))
	actualCapital = capital
	return

}

/*
打法4 固定出击份额的二仓出击位置函数 （激进）
出击位置1=0
出击位置2=max{ 0.77 +( -0.87 )*x1+( -0.61 )*x2+( -1.13 )*x3,出击位置1}
出击份额1=0.5
出击份额2=1-出击份额1
预测收益率= 0.89 +( 0.79 )*x1+( 0 )*x2+(-0.21 )*x3
*/
func methodNumber4(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	capital1 := int64(float64(capital)*0.5 + 0.5)
	methodResult.Prices = []int64{price1}
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((0.77+(-0.87)*xx1+(-0.61)*xx2+(-1.13)*xx3)*para1+0.5))
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	capital2 := capital - capital1
	if pos2 >= para2 { //只打第一仓
		return
	}
	if price1 == price2 { //出击位置1跟出击位置2相同 合并
		methodResult.Capitals[0] += capital2
		actualCapital = capital
		return
	}
	methodResult.Prices = append(methodResult.Prices, price2)
	methodResult.Capitals = append(methodResult.Capitals, capital2)
	methodResult.Pos = append(methodResult.Pos, int32(pos2))
	actualCapital = capital
	return
}

/*
打法5 不定出击份额的二仓出击位置函数 （激进）
出击位置1=0
出击位置2= max{0.77 +( -0.87 )*x1+( -0.61 )*x2+( -1.13 )*x3,出击位置1}
出击份额1=0.3
出击份额2=1-出击份额1
预测收益率= 1.25 +( 0.7 )*x1+(0 )*x2+( -0.29 )*x3
*/
func methodNumber5(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	capital1 := int64(float64(capital)*0.3 + 0.5)
	methodResult.Prices = []int64{price1}
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((0.77+(-0.87)*xx1+(-0.61)*xx2+(-1.13)*xx3)*para1+0.5))
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	capital2 := capital - capital1

	if pos2 >= para2 { //只打第一仓
		return
	}

	if price1 == price2 { //出击位置1跟出击位置2相同 合并
		methodResult.Capitals[0] += capital2
		actualCapital = methodResult.Capitals[0]
		return
	}
	methodResult.Prices = append(methodResult.Prices, price2)
	methodResult.Capitals = append(methodResult.Capitals, capital2)
	methodResult.Pos = append(methodResult.Pos, int32(pos2))
	actualCapital = capital
	return
}

/*
打法6 不定出击份额的三仓出击位置函数 （激进）
出击位置1=0
出击位置2=max{ 1.11 +( -0.73 )*x1+( -0.61 )*x2+( -2.35 )*x3,出击位置1}
出击位置3=max{ 0.62 +( -0.88 )*x1+( -0.62 )*x2+( -0.58 )*x3,出击位置2}
出击份额1=0.2
出击份额2=min{ 0.22 +( -0.01 )*x1+( 0.01 )*x2+( 0.37 )*x3,1-出击份额1}
出击份额3=1-出击份额1-出击份额2
预测收益率= 1.48 +( 0.67 )*x1+(0 )*x2+( -0.47 )*x3
*/
func methodNumber6(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	methodResult = new(util.MethodResult)
	actualCapital = 0
	xx1 := float64(x1) / weight
	xx2 := float64(x2) / weight
	xx3 := float64(x3) / weightx3
	price1 := price //基准价
	capital1 := int64(float64(capital)*0.2 + 0.5)
	methodResult.Prices = []int64{price1}
	methodResult.Capitals = []int64{capital1}
	methodResult.Pos = []int32{0}
	actualCapital = methodResult.Capitals[0]
	pos2 := util.Max(0, int64((1.11+(-0.73)*xx1+(-0.61)*xx2+(-2.35)*xx3)*para1+0.5))

	if pos2 >= para2 { //只打第一仓
		return
	}
	share2 := util.FMin(0.22+(-0.01)*xx1+(0.01)*xx2+(0.37)*xx3, 0.8)
	share2 = util.FMax(share2, 0)
	price2 := int64((float64(price1) * (para2 - float64(pos2)) / para2) + 0.5)
	capital2 := int64(float64(capital)*share2 + 0.5)
	if capital2 == 0 { // 第二仓分额 小于0，全仓打位置一
		methodResult.Capitals = []int64{capital}
		actualCapital = methodResult.Capitals[0]
		return
	}
	if price1 == price2 { //如果价格相等时
		methodResult.Capitals[0] += capital2
		actualCapital = methodResult.Capitals[0]

	} else {
		methodResult.Prices = append(methodResult.Prices, price2)
		methodResult.Capitals = append(methodResult.Capitals, capital2)
		methodResult.Pos = append(methodResult.Pos, int32(pos2))
		actualCapital += capital2
	}
	pos3 := util.Max(int64((0.62+(-0.88)*xx1+(-0.62)*xx2+(-0.58)*xx3)*para1+0.5), pos2)
	price3 := int64((float64(price1) * (para2 - float64(pos3)) / para2) + 0.5)
	capital3 := capital - capital1 - capital2
	if pos3 >= para2 { //位置3大于1000 只加第二仓
		return
	}
	if capital3 == 0 { //只打前两仓
		return
	}
	if price2 == price3 {
		methodResult.Capitals[len(methodResult.Capitals)-1] += capital3
		actualCapital = capital
		return
	}
	methodResult.Prices = append(methodResult.Prices, price3)
	methodResult.Capitals = append(methodResult.Capitals, capital3)
	methodResult.Pos = append(methodResult.Pos, int32(pos3))
	actualCapital = capital
	return
}

// 打法7 固定出击份额的二仓出击位置函数 （安全）
func methodNumber7(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	x1 = x1 - 2000
	x2 = x2 - 2000
	x3 = x3 - 20000
	return methodNumber1(x1, x2, x3, price, capital)
}

// 打法8 不定出击份额的二仓出击位置函数 （安全）
func methodNumber8(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	x1 = x1 - 2000
	x2 = x2 - 2000
	x3 = x3 - 20000
	return methodNumber2(x1, x2, x3, price, capital)
}

// 打法9 不定出击份额的三仓出击位置函数 （安全）
func methodNumber9(x1, x2, x3 int32, price, capital int64) (methodResult *util.MethodResult, actualCapital int64) {
	x1 = x1 - 2000
	x2 = x2 - 2000
	x3 = x3 - 20000
	return methodNumber3(x1, x2, x3, price, capital)
}
